/**
 *
 * 一个用于测量三维场景内的几何体的测量类 Measure.js
 *
 * Daniel
 *
 * 2018.03.12
 *
 * **/
define(function(){
    var Measure = function () {
        
        
        this.distance='';
        this.pointPath = "";
        
        this.mesureFlag=true;
        
        this.measureArray=[];
        this.measureIdArray=[];
        this.measureIdPointArray=[];
        this.lineObjectAr=[];
        
        this.measureObject={};
        this.measurePoint= {
            startPoint: [],
            endPoint: [],
        };
        this.mouseMonitor = {
            winX:null,
            winY:null
        };
        this.faceArea = null;
        
        this.pick = new function () {};
        this.scene = {};
        that= this;
        
        
    };
    
    Object.assign(Measure.prototype,{
    
    
    //初始化
        init : function(scene,pick,pointPath){
    
        this.pick = pick;
        this.scene = scene;
        this.pointPath = pointPath;
    },
    
    
    //预览绘制
        measureLines : function () {
        var scope = this;
        return function(event,callback){
            if(scope.mesureFlag){
                if (event) event.preventDefault();
                var flagss = scope.pick.mouseMonitor(event, scope.mouseMonitor);
                if (flagss == undefined) return;
                if (flagss.flag == 0 && flagss.offset) {
                    scope.mesureFlag = true;
                    scope.measureStartPoint(event,callback);
                }
                if(flagss.flag == 2){
                    scope.mesureFlag = false;
                }
                return scope;
            }
            
        };
    },
    
    //执行测量
        mesure : function (){
        var scope = this;
        return function (event) {
            if(scope.mesureFlag){
                var toPoint,startPoint,endPoint,flag,pointCarrier;
                
                toPoint = scope.pick.pick()(event);
                
                if( toPoint == undefined )return;
                
                flag = scope.measurePoint.startPoint;
                
                if(flag.length>0){
                    var start = scope.measureIdPointArray[0].clone();
                    var lines,flagss,name;
                    pointCarrier = scope.measureCompute(toPoint);
                    scope.createPoint(pointCarrier);
                    var targetPoint = pointCarrier.target.parent.parent.position.clone();
                    endPoint = pointCarrier.originalV.clone().add(targetPoint);
                    name = "lines";
                    flagss = scope.lineObjectAr;
                    if( flagss.length > 0 ){
                        var deleteLine = scope.lineObjectAr[0];
                        scope.scene.remove(deleteLine);
                        scope.lineObjectAr = [];
                        scope.measurePoint.endPoint = [];
                        lines = scope.drawLine(start,endPoint,name);
                        scope.scene.add(lines);
                    }else{
                        lines = scope.drawLine(start,endPoint,name);
                        scope.scene.add(lines);
                    }
                    
                }
                else{
                    startPoint = scope.measureCompute(toPoint);
                    scope.createPoint(startPoint);
                }
            }
            return scope;
        }
        
        
    },
    
    //移除测量
        removeMesure : function (){
        var scope = this;
        return function(){
            var points,line,fixLine,scene;
            points = scope.measureArray[0];
            line = scope.lineObjectAr[0];
            fixLine = scope.measureLine;
            scene = scope.scene;
            
            //移除现有的测量模型
            scene.remove(points);
            scene.remove(line);
            scene.remove(fixLine);
            
            //数据重置
            scope.measureArray = [];
            scope.measureIdArray=[];
            scope.lineObjectAr=[];
            scope.measureIdPointArray=[];
            scope.measurePoint.startPoint = [];
            scope.measureLine=null;
        };
    },
    
    //确定起始点
        measureStartPoint : function (event,callback){
        if(event) event.preventDefault();
        if(this.mesureFlag){
            var pickArray = this.measureArray;
            if(pickArray.length>0){
                var scene = this.scene;
                var pointObject = pickArray[0];
                var targetPoint = pointObject.target.parent.parent.position.clone();
                var start = pointObject.originalV.clone().add(targetPoint);
                var flag = this.measureIdPointArray;
                if(pickArray){
                    var c = pickArray;
                    
                }
                pointObject.material.opacity = 1;
                pointObject.material.transparent = false;
                this.measurePoint.startPoint.push(pointObject);
                scene.add(pointObject);
                if(flag.length==0){
                    this.measureIdPointArray.push(start);
                }
                if(flag.length>0){
                    var newStart = flag[0].clone();
                    var endP = start.clone();
                    var lines = this.drawLine(newStart,start,"lineFox");
                    var lineObj = this.measureLine;
                    if(lineObj == null){
                        scene.add(lines);
                    }
                    else{
                        scene.remove(lineObj);
                        scene.add(lines);
                    }
                    this.measureLine = lines;
                    
                    //模型的实际距离换算
                    var lengthss = newStart.distanceTo(start);
                    if( lengthss > 0 ){
                        this.distance = lengthss * 0.01;
                        //console.log("当前的长度为"+this.distance + "m");
                        if(callback)callback(this.distance);
                    }
                }
            }
        }
    },
    
    //测量
    
    //测量讫始点计算
        measureCompute : function (targetObject) {
        if(targetObject.length>0){
            var mother = targetObject[0];
            var faceIndex = mother.face;
            var geometrys = mother.object.geometry;
            var matrix = mother.object.matrixWorld;
            var vectorV = geometrys.vertices;
            var pointTarget = mother.point;
            var id = mother.object.id;
            var parent = mother.object;
            
            var vertexAA = new THREE.Vector3(),
                vertexBB = new THREE.Vector3(),
                vertexCC = new THREE.Vector3();
            
            //算法辅助参数
            var vertexA,vertexB,vertexC,faceVertexA,faceVertexB,
                faceVertexC,lengthA,lengthB,lengthC,euler,
                idName,vectors,originalV,transitionA,transitionB,transitionC,
                matrixP,matrixS,matrixR,
                goal = {
                    matrix:     "",
                    id:         "",
                    vectors:    "",
                    originalV:  ""
                };
            
            faceVertexA = faceIndex.a;
            faceVertexB = faceIndex.b;
            faceVertexC = faceIndex.c;
            
            matrixP = new THREE.Vector3();
            matrixS = new THREE.Vector3();
            matrixR = new THREE.Quaternion();
            
            euler = new THREE.Euler();
            euler.set(-0.5*Math.PI,0,0);
            matrix.decompose(matrixP,matrixR,matrixS);
            transitionA = vectorV[faceVertexA].clone().multiplyScalar(matrixS.x);
            transitionB = vectorV[faceVertexB].clone().multiplyScalar(matrixS.x);
            transitionC = vectorV[faceVertexC].clone().multiplyScalar(matrixS.x);
            
            vertexAA.set(transitionA.x,transitionA.z + matrixP.y,-transitionA.y);
            vertexBB.set(transitionB.x,transitionB.z + matrixP.y,-transitionB.y);
            vertexCC.set(transitionC.x,transitionC.z + matrixP.y,-transitionC.y);
            
            vertexA = vectorV[faceVertexA];
            vertexB = vectorV[faceVertexB];
            vertexC = vectorV[faceVertexC];
            
            lengthA = vertexAA .distanceTo(pointTarget);
            lengthB = vertexBB .distanceTo(pointTarget);
            lengthC = vertexCC .distanceTo(pointTarget);
            
            //计算最近顶点
            if(lengthA<lengthB){
                if(lengthA<lengthC){
                    vectors = vertexA;
                    originalV = vertexAA;
                    idName = id + faceVertexA;
                }else{
                    vectors = vertexC;
                    originalV = vertexCC;
                    idName = id + faceVertexC;
                }
            }
            else{
                if(lengthB<lengthC){
                    vectors = vertexB;
                    originalV = vertexBB;
                    idName = id + faceVertexB;
                }else{
                    vectors= vertexC;
                    originalV = vertexCC;
                    idName = id + faceVertexC;
                }
            }
            
            //返回最佳值
            goal.matrix = matrix;
            goal.id = idName;
            goal.vectors = vectors;
            goal.originalV = originalV;
            goal.target = parent;
            return goal;
        }
    },
    
    //测量点绘制
        createPoint : function (vectorObject,names) {
        //显示单个定点
        var flag = this.measureIdArray.indexOf(id);
        if( flag ==-1 ){
            var id,name,matrix,sphereInter;
            sphereInter = this.PointGeom(vectorObject,names);
            id = sphereInter.id;
            var oldPoint = this.measureArray[0];
            this.scene.remove(oldPoint);
            this.measureArray=[];
            this.measureIdArray=[];
            this.measureArray.push(sphereInter);
            this.measureIdArray.push(id);
            matrix = vectorObject.matrix;
            matrix.decompose(sphereInter.position,sphereInter.quaternion,sphereInter.scale);
            
            this.scene.add(sphereInter);
            
            name = sphereInter.name;
            sphereInter.originalV = vectorObject.originalV;
            this.measureObject[""+ name +""] = sphereInter.clone();
        }
        return sphereInter;
    },
    
    //测量点模型
        PointGeom : function (vectorObject,names){
        var goldGeom = new THREE.Geometry();
        var maps = new THREE.TextureLoader().load( this.pointPath );
        
        var goldmaterial = new THREE.PointsMaterial( { size: 15,color:0xff0000,map:maps,depthTest : false,transparent : true});
        var vector = vectorObject.vectors;
        var id = vectorObject.id;
        
        goldmaterial.opacity = 0.75;
        goldmaterial.transparent = true;
        goldGeom.vertices.push(vector);
        var sphereInter = new THREE.Points( goldGeom, goldmaterial );
        var name = names || "point"+id;
        sphereInter.name = name;
        sphereInter.target = vectorObject.target;
        return sphereInter;
    },
    
    //测量线绘制
        drawLine : function (startPoint,targetPoint,names) {
        var id,name;
        var material = new THREE.LineBasicMaterial({
            depthTest : false,
            transparent : true,
            color: 0xe6135c
        });
        var geometry = new THREE.Geometry();
        geometry.vertices.push(startPoint, targetPoint);
        var line = new THREE.Line( geometry, material );
        id = line.id;
        name = names || "line" + id;
        line.name = name;
        this.measureArray.push(line);
        this.measureIdArray.push(id);
        this.lineObjectAr.push(line);
        return line;
    },
    
    //计算几何属性
        //计算长度
        comLength:function (object) {
            var length;
            
            return length
        },
        //计算体积
        comVolume:function (object) {
            var volume = 0,allface = 0;
            var geo = object.geometry.attributes.position;
            var inde = object.geometry.index.array;
            var oreal = object.geometry.boundingSphere.center.clone();
            var vexters = [];
            var face = [],vorm=[];
            for(var i = 0; i < geo.count; i++){
                var vert = new THREE.Vector3(geo.array[i],geo.array[i+1],geo.array[i+2]);
                vexters.push(vert);
            }
            for(var k = 0; k < inde.length; k+=3){
                var a,b,c,aj,ak,al,normal,h,area,p,l,d,n,vol;
                    a= inde[k];
                    b= inde[k+1];
                    c= inde[k+2];
                    aj = new THREE.Vector3().subVectors(vexters[b],vexters[a]);
                    ak = new THREE.Vector3().subVectors(vexters[c],vexters[a]);
                    al = new THREE.Vector3().subVectors(vexters[c],vexters[b]);
                    l = aj.length();
                    d = ak.length();
                    n = al.length();
                    p = (l+n+d)/2;
                    normal = new THREE.Vector3().crossVectors(aj,ak);
                    h = oreal.projectOnPlane(normal).length();
                    area = Math.sqrt(p*(p-l)*(p-n)*(p-d));
                    vol = (area*h)/3;
                    if(isNaN(vol)) vol = 0;
                    vorm.push(vol);
                    face.push(area);
            }
            vorm.forEach(function(em){
                volume+=em;
            });         //总体积
            face.forEach(function(em){
                allface+=em;
            });//总表面积
            that.faceArea = allface;
            return volume
        },
        //计算表平面
        comParea:function (object) {
            var parea;
            parea = that.faceArea;
            return parea
    },
        //计算曲表面
        comHarea:function (object) {
            var harea;
    
            return harea
        },
        //计算总面积
        comTarea:function (object) {
            var tarea;
    
            return tarea
        },
        
        //汇总计算
    compute:function(object,objContainer){
        if(!object)return objContainer;
        objContainer.length = that.comLength(object);
        objContainer.volume = that.comVolume(object);
        objContainer.parea = that.comParea(object);
        objContainer.harea = that.comHarea(object);
        objContainer.tarea = that.comTarea(object);
        return objContainer
    }
    
});
   var that;
    
    return Measure;
    
    
    
});